-
-
Notifications
You must be signed in to change notification settings - Fork 644
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow more types of dictionary keys in overrides grammar #1208
Conversation
website/versioned_docs/version-1.0/advanced/override_grammar/basic.md
Outdated
Show resolved
Hide resolved
tests/test_hydra.py
Outdated
@@ -1047,6 +1047,29 @@ def test_run_pass_list(self, cmd_base: List[str], tmpdir: Any) -> None: | |||
ret, _err = get_run_output(cmd) | |||
assert OmegaConf.create(ret) == OmegaConf.create(expected) | |||
|
|||
def test_multirun_dict_keys(self, cmd_base: List[str], tmpdir: Any) -> None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test, and test_overrides_dict_keys - are very high level.
you have some low level tests in test_overrides_parser and you are jumping straight into testing as processes.
If I understand the purpose of those tests correctly (and it's hard because they are so high level), I think should should be replaced by lower level config composition test in test_config_loader.py.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, to clarify the motivation: those two new tests are meant to test the changes in types.py
(which are not tested by the low level grammar tests)
The second one (test_overrides_dict_keys
) should probably indeed be a lower level test. I wasn't familiar with the various Hydra tests and couldn't figure out where the basic override functionalities were being tested. I just moved it to test_config_loader.py
as you suggested: see 6bcaac2, let me know if that makes more sense this way. The main thing that needs to be tested is quoted strings as keys, but I thought it wouldn't hurt to add tests for all other kinds of string formatting that we may expect, just in case (also later on, we should also test other types of keys like int / float / bool if we support them).
I'm not sure I can move test_multirun_dict_keys
to this same file though. This test specifically tests the change to _get_value_element_as_str()
(l. 429 of types.py in the current diff of this PR), which is used in sweeps to provide the proper command line overrides. Again, the main thing that needs testing are quoted strings, but I added the other key formats as well to be safe.
Maybe to clarify the purpose of this test, I can show you how it fails if I revert the l.429 change:
LexerNoViableAltException: +foo={QuotedString(text='null', quote=<Quote.single: 0>):0}
(this is because the sweeper would not replace the QuotedString
with its actual quoted string representation in the command line override)
Side note: I also pushed 0b53209 which removes some comments that seemed irrelevant to me (probably a copy/paste leftover from another comment you can see below them)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great.
There is a test in test_overrides_parser that is dedicated for that logic: test_override_get_value_element_method
I think testing there should be sufficient.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think testing there should be sufficient.
Perfect! Done in 8084317
At the same time I uncovered a bug with escaped characters (that affected regular unquoted strings as well, not just dictionary keys), which is now fixed in that same commit.
I commented about the high level tests.
I suspect OmegaConf dict keys should also not support interpolation for the same reasons.
Sounds good. I saw that you actually did rename dictValue to dictContainer in the tests. anything else you left as is?
Commented inline.
Does they work when sweeping over dictionaries?
Commented line, revert. this is for 1.1.
I think we need a news fragment, but first we need to pin point exactly what this is enabling. |
Thanks for the review & comments!
Currently dictionaries in OmegaConf's grammar are used for a different purpose though: they are only inputs to resolvers. So these questions don't actually arise.
Yeah, so if you search for
Why would they? > python my_app.py +foo="{a:10},{10:a}" -m 1 ↵ 2.48 L
Error merging override +foo={10:a}
Incompatible key type 'int'
full_key: foo.10
reference_type=Any
object_type=dict Note that I used
If we merge it in current master, it allows command line overrides with dictionaries whose keys are strings in "non ID" format (see In the future, it should allow also command line overrides with dictionaries whose keys are not strings (ex: int, float, bool). But that can only happen after OmegaConf supports those. |
tests/test_hydra.py
Outdated
@@ -1047,6 +1047,29 @@ def test_run_pass_list(self, cmd_base: List[str], tmpdir: Any) -> None: | |||
ret, _err = get_run_output(cmd) | |||
assert OmegaConf.create(ret) == OmegaConf.create(expected) | |||
|
|||
def test_multirun_dict_keys(self, cmd_base: List[str], tmpdir: Any) -> None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great.
There is a test in test_overrides_parser that is dedicated for that logic: test_override_get_value_element_method
I think testing there should be sufficient.
Also made the `QuotedString` dataclass immutable for hash safety.
Also improved the corresponding tests for dictionary keys.
Side note: I removed a print statement that seemed out of place in fc87464 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, a couple of small comments.
Looking good @odelalleau, I am ready to merge it. |
@jieru-hu , probably unrelated to this PR: |
Hi, how to parse something like I tried a simpler dictKey like |
Using single quotes |
Thanks so much for the quick response. Single quotes doesn't work for me. I just found a working solution: |
Hmm, I think either:
The solution you found gives a different result: it sets To check your shell behavior, you can do: > python -c "import sys; print(sys.argv[1])" 'key={/-\\+.$%*@: 1}'
key={/-\\+.$%*@: 1} |
This works for me, but Hydra 1.1 is not compatible with our code. Do you know it will be released? |
There are indeed a bunch of changes from 1.0 to 1.1 you'll need to take care of (you can start here: https://hydra.cc/docs/next/upgrades/intro) AFAIK the official release of 1.1 is still a few weeks from now. You can give the RC1 a shot (see release notes at https://github.com/facebookresearch/hydra/releases/tag/v1.1.0.rc1) but there might still be a few rough edges, so don't use it in a critical application just yet. If you want to stick to 1.0 I'm afraid there aren't many options -- you might be able to hack something around with a custom resolver but the 1.0 resolvers are a bit limited so it probably wouldn't be great. A simpler temporary hack (until you upgrade to 1.1) could be to replace whatever character that is not allowed in 1.0 with |
At this point I recommend that you migrate to Hydra 1.1 by installing the first release candidate and fixing all the warnings. |
Motivation
Requested in omry/omegaconf@d959a13#r45076606
Remarks & questions
I wasn't entirely sure where to put this test: https://github.com/odelalleau/hydra/blob/ccde9814d66042f4c6b9fe7ec3db77e253297265/tests/test_hydra.py#L1190 . It's important to have it in addition to the grammar tests in test_overrides_parser because it also tests the config merge (in particular, it matters for quoted strings). Also ideally this would have been a parameterized test, but since
integration_test()
is slow, I thought it would be more convenient to have a single test to avoid slowing down the test suite even more.Compared to what I did in OmegaConf, I'm not supporting interpolations as dictionary keys in Hydra's overrides grammar. This is because dictionaries in Hydra are meant to be merged into DictConfigs, and allowing interpolations would raise several questions that I believe are better left for later (should we resolve interpolations before or after merging overrides? do we allow keys to change names dynamically?).
As in my OmegaConf PR, I renamed
dictValue
andlistValue
todictContainer
andlistContainer
, to avoid any confusion that may arise due to the newdictKey
parser rule. However, this change impacts more things in Hydra than it did in OmegaConf. Let me know if that's still ok (edit: I should add that there remain someDictValues
andListValues
in tests that I didn't change, as I wasn't entirely sure if the "value" there was directly related to the name of the rules)When implementing equality for quoted strings, it made sense to me to ignore the type of quotes in
__eq__
. It also didn't break any existing test. Just wanted to flag it here in case it might be a concern.In this PR the grammar allows non-string dictionary keys like int / float / bool, but in practice trying to use them will not work since OmegaConf does not support them currently. Not sure if I should keep them to be "future proof", or just remove them for now.
I assumed this would make it into 1.0.x and thus I updated the 1.0 doc as well. If that's not the case let me know and I'll revert this change.
I didn't add a news item yet as it didn't really seem worth one on its own (the ability to use non-string keys would be more meaningful to advertise IMO)
Test Plan
pytest (see new tests in the diff)
Related Issues and PRs
Related to omry/omegaconf#445